/*
EP3D is a real-time 3D planet engine , which in addition to providing 
substandard scene rendering and scene management, of course, it also 
provides some basic class libraries to build the entire virtual 
planet, or even the entire universe.

Copyright (C) 2010  Hongjiang Zhang	(zhjwyat@gmail.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "EP3DAttributes.h"
#include "EP3DXMLStream.h"
#include "EP3DIntAttribute.h"
#include "EP3DF32Attribute.h"
#include "EP3DF64Attribute.h"
#include "EP3DBoolAttribute.h"
#include "EP3DStringAttribute.h"
#include "EP3DStringArrayAttribute.h"
#include "EP3DEnumAttribute.h"

namespace EP3D
{
	Attributes::Attributes(void)
	{
	}

	Attributes::~Attributes(void)
	{
		Clear();
	}

	 uint Attributes::GetAttributeCount() const
	 {
		 return m_akAttributes.GetSize();
	 }

	 AttributeType Attributes::GetAttributeType(const TCHAR* name)
	 {
		 AttributeType ret = AT_UNKNOWN;
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 ret = attr->GetType();
		 }

		 return ret;
	 }

	 const TCHAR* Attributes::GetAttributeTypeString(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetTypeString();
		 }
		 else {
			 return TEXT("unknown");
		 }
	 }

	 bool Attributes::IsExistAttribute(const TCHAR* name)
	 {
		 return GetAttributeByName(name) != NULL;
	 }

	 void Attributes::Clear()
	 {
		 m_akAttributes.Clear();
	 }

	 bool Attributes::Write(XMLWriter* pkWriter, bool bWriteHeader, const wchar_t* elementname)
	 {
		 if (!pkWriter) {
			 return false;
		 }

		 if (bWriteHeader) {
			 pkWriter->WriteXMLHeader();
		 }

		 StringW kName = L"Attributes";
		 if (NULL != elementname) {
			 kName = elementname;
		 }

		 pkWriter->WriteElement(kName, false);
		 pkWriter->WriteLineBreak();

		 for (uint i = 0; i < m_akAttributes.GetSize(); ++i) {
			 if (m_akAttributes[i]->GetType() == AT_STRINGARRAY) {
				 Array<StringW> akNameArray, akValueArray;
				 Array<String> akInputArray = m_akAttributes[i]->GetStringArray();

#if _UNICODE
				 akNameArray.Add(L"name");
				 akValueArray.Add(m_akAttributes[i]->m_kName);

				 akNameArray.Add(L"count");
				 StringW tempValue;
				 tempValue.Format(L"%d", akInputArray.GetSize());
				 akValueArray.Add(tempValue);

				 StringW tempName;
				 for (uint n = 0; n < akInputArray.GetSize(); ++n) {
					 tempName.Format(L"value%d", n);
					 akNameArray.Add(tempName);
					 akValueArray.Add(akInputArray[n]);
				 }

				 pkWriter->WriteElement(
					 m_akAttributes[i]->GetTypeString(), 
					 true, 
					 akNameArray, 
					 akValueArray);

#else

				 akNameArray.Add(L"name");
				 akValueArray.Add(StringAtoW(m_akAttributes[i]->m_kName));

				 akNameArray.Add(L"count");
				 StringW tempValue;
				 tempValue.Format(L"%d", akInputArray.GetSize());
				 akValueArray.Add(tempValue);

				 StringW tempName;
				 for (uint n = 0; n < akInputArray.GetSize(); ++n) {
					 tempName.Format(L"value%d", n);
					 akNameArray.Add(tempName);
					 akValueArray.Add(StringAtoW(akInputArray[n]));
				 }

				 pkWriter->WriteElement(
					 StringAtoW(m_akAttributes[i]->GetTypeString()), 
					 true, 
					 akNameArray, 
					 akValueArray);
#endif
			 }
			 else {
#if _UNICODE
				 pkWriter->WriteElement(
					 m_akAttributes[i]->GetTypeString(),
					 true,
					 L"name", m_akAttributes[i]->m_kName,
					 L"value",  m_akAttributes[i]->GetString()
					 );
#else
				 pkWriter->WriteElement(
					 StringAtoW(m_akAttributes[i]->GetTypeString()),
					 true,
					 L"name", StringAtoW(m_akAttributes[i]->m_kName),
					 L"value",  StringAtoW(m_akAttributes[i]->GetString()));
#endif	 
			 }

			 pkWriter->WriteLineBreak();
		 }

		 pkWriter->WriteClosingTag(kName);
		 pkWriter->WriteLineBreak();

		 return true;
	 }

	 void Attributes::AddInt(const TCHAR* name, int val)
	 {
		 m_akAttributes.Add(EP3DNew IntAttribute(name, val));
	 }

	 void Attributes::AddF32(const TCHAR* name, f32 val)
	 {
		 m_akAttributes.Add(EP3DNew F32Attribute(name, val));
	 }

	 void Attributes::AddF64(const TCHAR* name, f64 val)
	 {
		 m_akAttributes.Add(EP3DNew F64Attribute(name, val));
	 }

	 void Attributes::AddBool(const TCHAR* name, bool val)
	 {
		 m_akAttributes.Add(EP3DNew BoolAttribute(name, val));
	 }

	 void Attributes::AddString(const TCHAR* name, const TCHAR* val)
	 {
		 m_akAttributes.Add(EP3DNew StringAttribute(name, val));
	 }

	 void Attributes::AddStringArray(const TCHAR* name, const StringArray& val)
	 {
		 m_akAttributes.Add(EP3DNew StringArrayAttribute(name, val));
	 }

	 void Attributes::AddEnum(const TCHAR* name, const TCHAR* val, const TCHAR* const* literals)
	 {
		 m_akAttributes.Add(EP3DNew EnumAttribute(name, val, literals));
	 }

	 void Attributes::AddEnum(const TCHAR* name, int val, const TCHAR* const* literals)
	 {
		 AddEnum(name, TEXT(""), literals);
		 m_akAttributes.Back()->SetInt(val);
	 }

	 void Attributes::SetAttribute(const TCHAR* name, int val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetInt(val);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew IntAttribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, f32 val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetF32(val);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew F32Attribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, f64 val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetF64(val);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew F64Attribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, bool val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetBool(val);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew BoolAttribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, const TCHAR* val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 if (!val) {
				 m_akAttributes.Erase(m_akAttributes.LinearSearch(attr));
			 }
			 else {
				 attr->SetString(val);
			 }
		 }
		 else {
			 m_akAttributes.Add(EP3DNew StringAttribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, const StringArray& val)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetStringArray(val);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew StringArrayAttribute(name, val));
		 }
	 }

	 void Attributes::SetAttribute(const TCHAR* name, const TCHAR* val, const TCHAR* const* literals)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 attr->SetEnum(val, literals);
		 }
		 else {
			 m_akAttributes.Add(EP3DNew EnumAttribute(name, val, literals));
		 }
	 }

	 int Attributes::GetAttributeAsInt(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetInt();
		 }

		 return 0;
	 }

	 f32 Attributes::GetAttributeAsF32(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetF32();
		 }

		 return 0.0f;
	 }

	 f64 Attributes::GetAttributeAsF64(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetF64();
		 }

		 return 0.0f;
	 }

	 bool Attributes::GetAttributeAsBool(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetBool();
		 }

		 return false;
	 }

	 String Attributes::GetAttributeAsString(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetString();
		 }

		 return String();
	 }

	 StringArray Attributes::GetAttributeAsStringArray(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetStringArray();
		 }

		 return StringArray();
	 }

	 const TCHAR* Attributes::GetAttributeAsEnumeration(const TCHAR* name)
	 {
		 AttributePtr attr = GetAttributeByName(name);
		 if (!attr.IsNull()) {
			 return attr->GetEnum();
		 }
		 else {
			 return 0;
		 }
	 }

	 AttributePtr Attributes::GetAttributeByName(const TCHAR* name)
	 {
		 for (uint i = 0; i < m_akAttributes.GetSize(); ++i) {
			 if (m_akAttributes[i]->m_kName == name) {
				 return m_akAttributes[i];
			 }
		 }

		 return NULL;
	 }

}
